package com.googlecode.monitoria.server.persistence.util;

 import org.apache.log4j.Logger;
import org.apache.log4j.spi.RootLogger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;

import com.googlecode.monitoria.client.beans.User;
import com.googlecode.monitoria.client.beans.UserType;
import com.googlecode.monitoria.server.persistence.dao.AbstractDAO.DAOFactory;
import com.googlecode.monitoria.server.persistence.dao.DAO;

/**
 * @author Ricardo Araújo Santos - ricardo@lsd.ufcg.edu.br
 *
 */
public class HibernateUtil {

	private static final SessionFactory sessionFactory;
	private static Logger logger = RootLogger.getLogger(HibernateUtil.class);

    static {
        try {
            sessionFactory = new AnnotationConfiguration().addAnnotatedClass(User.class).configure().buildSessionFactory();
        } catch (Throwable ex) {
        	logger.error(ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    
    public static void setup(){
   	
   		DAO<User> userDAO = DAOFactory.getUserDAO();
   		userDAO.save( new User( "admin", "admin", UserType.TEACHER ) );
    }

    /**
     * Opens a new session. 
     * @return A new session
     * @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
		Session session = (Session) sessionFactory.getCurrentSession();
		try {
			if (session == null || !session.isOpen()) {
				logger.debug("Opening new Session for this thread.");
				session = sessionFactory.openSession();
			}
		} catch (HibernateException ex) {
			logger.error("getSession", ex);
		}
		return session;
    }

	public static void closeSession() {
		try {
			Session session = (Session) sessionFactory.getCurrentSession();
			//threadSession.set(null);
			if (session != null && session.isOpen()) {
				logger.trace("Closing Session of this thread.");
				session.close();
			}
		} catch (HibernateException ex) {
			logger.error("closeSession", ex);
		}
	}

	public static void beginTransaction() {
		Transaction tx = (Transaction) sessionFactory.getCurrentSession().beginTransaction();
		try {
			if (tx == null) {
				logger.trace("Starting new database transaction in this thread.");
				tx = getSession().beginTransaction();
				//threadTransaction.set(tx);
			}
		} catch (HibernateException ex) {
			logger.error("beginTransaction", ex);
		}
	}

	public static void commitTransaction() {
		Transaction tx = (Transaction) sessionFactory.getCurrentSession().getTransaction();
		try {
			if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
				logger.trace("Committing database transaction of this thread.");
				tx.commit();
			}
			//threadTransaction.set(null);
		} catch (HibernateException ex) {
			rollbackTransaction();
			logger.error("commitTransaction", ex);
		} finally {
			closeSession();
		}
	}

	public static void rollbackTransaction() {
		Transaction tx = (Transaction) sessionFactory.getCurrentSession().getTransaction();
		try {
			//threadTransaction.set(null);
			if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
				logger.trace("Tyring to rollback database transaction of this thread.");
				tx.rollback();
			}
		} catch (HibernateException ex) {
			logger.error("rollbackTransaction", ex);
		}
	}

	public static void rollbackAndCloseSession() {
		rollbackTransaction();
		closeSession();
	}

}
